﻿#region

using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
using Vin.Tool.Attributes;
using Vin.Tool.Core.AssemblyCategory;
using Vin.Tool.Domain.SystemModel;
using Vin.Tool.Enums;

#endregion

namespace Vin.Tool.AspNetCore.Extension;

public static class RegisterModelExtension
{
    public static void AddRegisterModelExtension(this IServiceCollection services, List<RegisterModel> types)
    {
        foreach (var type in types)
        {
            switch (type.Lifetime)
            {
                case Lifetime.Scoped:
                    services.AddScoped(type.Type);
                    break;
                case Lifetime.Singleton:
                    services.AddSingleton(type.Type);
                    break;
                case Lifetime.Transient:
                    services.AddTransient(type.Type);
                    break;
            }
        }
    }

    private static void AddService(IServiceCollection serviceCollection, Type serviceType,
        Type implementationType, RegisterModel registerModel)
    {
        switch (registerModel.Lifetime)
        {
            case Lifetime.Scoped:
                serviceCollection.AddScoped(serviceType, implementationType);
                break;
            case Lifetime.Singleton:
                serviceCollection.AddSingleton(serviceType, implementationType);
                break;
            case Lifetime.Transient:
                serviceCollection.AddTransient(serviceType, implementationType);
                break;
        }
    }

    public static void AddRegisterModelExtension(this IServiceCollection services)
    {
        var allCustomRepository = AssemblyTool.GetTypesByAttribute<ModelAttribute>().Select(m =>
        {
            var attr = m.GetCustomAttribute<ModelAttribute>()!;
            return new RegisterModel()
            {
                Type = m,
                Lifetime = attr.Lifetime
            };
        }).ToList();
        // services.AddRegisterModelExtension(allCustomRepository);

        foreach (var item in allCustomRepository)
        {
            // 忽略标记了忽略服务的接口
            if (item.Type.IsDefined(typeof(IgnoreServiceAttribute))) continue;

            // 先注入自身
            AddService(services, item.Type, item.Type, item);

            // 如果指定了单个接口，则注入指定的接口
            if (item.InterfaceType != null)
            {
                AddService(services, item.InterfaceType, item.Type, item);
                continue;
            }

            // 全部接口注入
            var interfaces = item.Type.GetInterfaces();
            foreach (var interfaceType in interfaces)
            {
                // 忽略标记了忽略服务的接口
                if (interfaceType.IsDefined(typeof(IgnoreServiceAttribute))) continue;

                // 如果是泛型
                if (interfaceType.IsGenericType || item.Type.IsGenericType)
                {
                    // 且泛型参数个数不一致，类型不一致，则忽略
                    if (!interfaceType.GetGenericArguments().SequenceEqual(item.Type.GetGenericArguments())) continue;
                }

                var serviceType = interfaceType;
                if (interfaceType.IsGenericType)
                {
                    // item.attr.InterfaceType = item.type.MakeGenericType(item.attr.InterfaceType.GenericTypeArguments);
                    // item.attr.InterfaceType = item.attr.InterfaceType.GetGenericTypeDefinition();
                    // serviceType = item.type.MakeGenericType(serviceType.GenericTypeArguments);
                    serviceType = interfaceType.GetGenericTypeDefinition();
                }

                AddService(services, serviceType, item.Type, item);
            }
        }
    }
}